import math
import json
from data_processing.song import Song
import os
from tqdm import tqdm
from data_processing.image_draw import draw_text
from data_processing.logger import logger

ARGUMENT = 22.512
info_path = 'out/chosen_info.json'
output_json_path = f'out/answer.json'


def algo(left, right, rating, output_type):
    b35_rating = int(rating * 35 / 50)
    output_path = f'out/diff [{left}-{right}] to rating[{rating}].txt'

    # 计算鸟加时定数的贡献
    rating_map = dict()
    for num in [i for i in range(int(left * 10), int(right * 10) + 1)]:
        num = num / 10
        rating_map[num] = math.floor(num * ARGUMENT)

    # 加载数据
    data_list = []
    data_dict = dict()
    min_diff_level = 0x3fffffff
    max_diff_level = 0
    with open(info_path, 'r', encoding='utf-8') as info_file:
        info_datas = json.load(info_file)
    for info_data in info_datas.values():
        exp = info_data.get('exp_level', None)
        mas = info_data.get('mas_level', None)
        rem = info_data.get('rem_level', None)
        for map in [exp, mas, rem]:
            if map is not None:
                diff_level = round(map['level'][1], 4)
                min_diff_level = min(min_diff_level, diff_level)
                max_diff_level = max(max_diff_level, diff_level)
                data_list.append(Song(map['title'], rating_map.get(map['level'][0]), diff_level))
                data_dict[map['title']] = {
                    'level': map['level'][0],
                    'diff_level': round(map['level'][1], 4)
                }

    # 归一化处理中分界映射为1-100
    scale = 99 / (max_diff_level - min_diff_level)
    for data in data_list:
        data.diff_level = int((data.diff_level - min_diff_level) * scale) + 1
    logger.info(f'拟合定数最小值: {min_diff_level}, 拟合定数最大值: {max_diff_level}')

    # 在 data_list:k个物品 中找到 35首歌:j(重量2) 满足 sum(diff_level):i(重量1) 尽可能最小,且 sum(rating)>B35_rating:输出的边界条件(价值)
    ans = 0x3fffffff
    title_list = [[list() for _ in range(0, 36)] for _ in range(0, 3501)]
    ans_title_list = []
    sum_rating = 0
    dp = [[0 for _ in range(0, 36)] for _ in range(0, 3501)]
    for data in tqdm(data_list, desc='执行进度', mininterval=0.5):
        value = data.rating
        weight = data.diff_level
        for i in range(3500, weight - 1, -1):
            for j in range(35, 0, -1):
                if (dp[i - weight][j - 1] + value) > dp[i][j]:
                    dp[i][j] = dp[i - weight][j - 1] + value
                    title_list[i][j] = title_list[i - weight][j - 1].copy()
                    title_list[i][j].append(data.title)
                if dp[i][j] > b35_rating and j == 35:
                    if i < ans:
                        ans = i
                        ans_title_list = title_list[i][j]
                        sum_rating = dp[i][j]

    # 输出数据
    output_dict = dict()
    avg_diff_level = 0
    avg_level = 0
    for data in ans_title_list:
        output_dict[data] = data_dict[data]
        avg_diff_level += data_dict[data]['diff_level']
        avg_level += data_dict[data]['level']
    avg_diff_level = round(1.0 * avg_diff_level / 35, 4)
    avg_level = round(1.0 * avg_level / 35, 4)

    if os.path.exists(info_path):
        os.remove(info_path)
    if output_type == 'json':
        output_dict['总计rating'] = sum_rating
        output_dict['平均拟合定数'] = avg_diff_level
        output_dict['平均定数'] = avg_level
        with open(output_json_path, 'w', encoding='utf-8') as output_file:
            json.dump(output_dict, output_file, indent=4, ensure_ascii=False)
    else:
        sorted_list = [(key, value) for key, value in sorted(output_dict.items(), key=lambda x: x[1]['level'])]
        with open(output_path, 'w', encoding='utf-8') as output_file:
            output_file.write(f'只选择定数 {left} - {right} 之间的鸟加达到 {rating} ra所需拟合定数最小的b35\n')
            for index, (key, field) in enumerate(sorted_list):
                output_file.write(f'{index + 1}. {key}: [')
                if isinstance(field, dict):
                    field_list = list(field.items())
                    for i, (field_key, value) in enumerate(field_list):
                        if field_key == 'diff_level':
                            print_key = '拟合定数'
                        elif field_key == 'level':
                            print_key = '定数'
                        output_file.write(f'{print_key}:{value}')
                        if i < len(field) - 1:
                            output_file.write(' ')
                output_file.write(']\n')
            output_file.write(f'\n总计rating: {sum_rating}\n平均拟合定数: {avg_diff_level}\n平均定数: {avg_level}\n\n')
        if output_type == 'png':
            draw_text(output_path)
            if os.path.exists(output_path):
                os.remove(output_path)

    logger.info('计算完成!')
